home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / ramfs.zoo / ramfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-16  |  26.0 KB  |  1,100 lines

  1. /*
  2.  * 'RAMFS': A (resizable) ramdisk file system for MiNT
  3.  * Author : Thierry Bousch
  4.  * Version: 1.4 (August 1993)
  5.  *
  6.  * Revision history:
  7.  * 1.0    Added version number, and macro-ized TRACE so that it is possible
  8.  *    to compile with or without debug information.
  9.  * 1.1  Added setuid, setgid and sticky bit for directories. Macro-ized
  10.  *      also DEBUG, ALERT and FATAL.
  11.  * 1.2  Deleted open files are now hidden. Added the valid_name() function.
  12.  *      Added a test in ram_rename about sticky directories.
  13.  * 1.3  Deleted open files are now put in a special place (the trash-list)
  14.  *      instead of leaving them half-deleted in their directories.
  15.  *      Added support for the FTRUNCATE ioctl call.
  16.  * 1.4  Take advantage of the FS_MOUNT call in MiNT 1.08, so that we can
  17.  *      get rid of drive R. Added FS_LONGPATH support.
  18.  *      The size of the RAMFILE structure is now considered in the getxattr
  19.  *      and dfree functions.
  20.  */
  21.  
  22. #include <string.h>
  23. #include "atarierr.h"
  24. #include "filesys.h"
  25.  
  26. #define VERSION  "1.4"
  27.  
  28. /*
  29.  * You may edit the following constants:
  30.  *
  31.  *    RAM_NAME    name of the ramdisk-fs directory
  32.  *    RAMFILE_MAX    maximum length of a filename
  33.  *    BLKSIZE        chunk size (must be a power of two)
  34.  *
  35.  * Define the symbols NO_{TRACE,DEBUG,ALERT,FATAL} to disable trace,
  36.  * debug, alert and fatal calls, respectively.
  37.  */
  38.  
  39. #define RAM_NAME    "U:\\ram"
  40. #define RAMFILE_MAX    35
  41. #define BLKSIZE        512L
  42. #define NO_TRACE
  43.  
  44. /*
  45.  * this points to the structure that has all the useful functions that
  46.  * the kernel told us about
  47.  */
  48.  
  49. struct kerinfo *kernel;
  50.  
  51. #define CCONWS        (*kernel->dos_tab[0x09])
  52. #define DCNTL        (*kernel->dos_tab[0x130])
  53.  
  54. #define Timestamp    (*kernel->dos_tab[0x2c])
  55. #define Datestamp    (*kernel->dos_tab[0x2a])
  56. #define FreeMemory()    (*kernel->dos_tab[0x48])(-1L)
  57. #define Getpid        (*kernel->dos_tab[0x10b])
  58. #define Getuid        (*kernel->dos_tab[0x10f])
  59. #define Getgid        (*kernel->dos_tab[0x114])
  60. #define Geteuid        (*kernel->dos_tab[0x138])
  61. #define Getegid        (*kernel->dos_tab[0x139])
  62.  
  63. #define Kmalloc        (*kernel->kmalloc)
  64. #define Kfree        (*kernel->kfree)
  65. #define Stricmp        (*kernel->stricmp)
  66. #define Denyshare    (*kernel->denyshare)
  67.  
  68. #ifndef NULL
  69. # define NULL        ((void *)0L)
  70. #endif
  71.  
  72. #define FTRUNCATE    (('F'<< 8) | 4)        /* from the Minix FS */
  73.  
  74. /* Useful macros */
  75.  
  76. #define IS_DIRECTORY(s)    (((s)->mode & S_IFMT) == S_IFDIR)
  77. #define IS_SYMLINK(s)    (((s)->mode & S_IFMT) == S_IFLNK)
  78. #define IS_SETUID(s)    ((s)->mode & S_ISUID)
  79. #define IS_SETGID(s)    ((s)->mode & S_ISGID)
  80. #define IS_STICKY(s)    ((s)->mode & S_ISVTX)
  81.  
  82. /* Conditional debugging */
  83.  
  84. #ifdef NO_DEBUG
  85. # define DEBUG(x)
  86. #else
  87. # define DEBUG(x)    (*kernel->debug)x
  88. #endif
  89.  
  90. #ifdef NO_ALERT
  91. # define ALERT(x)
  92. #else
  93. # define ALERT(x)    (*kernel->alert)x
  94. #endif
  95.  
  96. #ifdef NO_TRACE
  97. # define TRACE(x)
  98. #else
  99. # define TRACE(x)    (*kernel->trace)x
  100. #endif
  101.  
  102. #ifdef NO_FATAL
  103. # define FATAL(x)
  104. #else
  105. # define FATAL(x)    (*kernel->fatal)x
  106. #endif
  107.  
  108. /* Forward declarations of the file system functions */
  109.  
  110. long    ram_root    (int drv, fcookie *fc);
  111. long    ram_lookup    (fcookie *dir, char *name, fcookie *fc);
  112. long    ram_creat    (fcookie *dir, char *name, unsigned mode,
  113.                 int attrib, fcookie *fc);
  114. DEVDRV*    ram_getdev    (fcookie *fc, long *devsp);
  115. long    ram_getxattr    (fcookie *fc, XATTR *xattr);
  116. long    ram_chattr    (fcookie *fc, int attrib);
  117. long    ram_chown    (fcookie *fc, int uid, int gid);
  118. long    ram_chmode    (fcookie *fc, unsigned mode);
  119. long    ram_mkdir    (fcookie *fc, char *name, unsigned mode);
  120. long    ram_rmdir    (fcookie *dir, char *name);
  121. long    ram_remove    (fcookie *dir, char *name);
  122. long    ram_getname    (fcookie *root, fcookie *dir, char *path, int size);
  123. long    ram_rename    (fcookie *olddir, char *oldname,
  124.                 fcookie *newdir, char *newname);
  125. long    ram_opendir    (DIR *dirh, int flags);
  126. long    ram_readdir    (DIR *dirh, char *nm, int nmlen, fcookie *fc);
  127. long    ram_rewinddir    (DIR *dirh);
  128. long    ram_closedir     (DIR *dirh);
  129. long    ram_pathconf     (fcookie *dir, int which);
  130. long    ram_dfree    (fcookie *dir, long *buf);
  131. long    ram_writelabel    (fcookie *dir, char *name);
  132. long    ram_readlabel    (fcookie *dir, char *name, int namelen);
  133. long    ram_symlink    (fcookie *dir, char *name, char *to);
  134. long    ram_readlink    (fcookie *dir, char *buf, int len);
  135. long    ram_hardlink    (fcookie *fromdir, char *fromname,
  136.                 fcookie *todir, char *toname);
  137. long    ram_fscntl    (fcookie *dir, char *name, int cmd, long arg);
  138. long    ram_dskchng    (int drv);
  139.  
  140. /* Forward declarations of the device driver functions */
  141.  
  142. long    ram_open    (FILEPTR *f);
  143. long    ram_write    (FILEPTR *f, char *buf, long bytes);
  144. long    ram_read    (FILEPTR *f, char *buf, long bytes);
  145. long    ram_lseek    (FILEPTR *f, long where, int whence);
  146. long    ram_ioctl    (FILEPTR *f, int mode, void *buf);
  147. long    ram_datime    (FILEPTR *f, int *time, int rwflag);
  148. long    ram_close    (FILEPTR *f, int pid);
  149. long    ram_select    (FILEPTR *f, long p, int mode);
  150. void    ram_unselect    (FILEPTR *f, long p, int mode);
  151.  
  152. /* 
  153.  * Here is the structure used for ram files. The "next" field points to
  154.  * the following file/dir in that directory. The "up" field points to the 
  155.  * directory the file/dir is in, or NULL for the root directory. The
  156.  * "down" field is only used by subdirectories and points to the first
  157.  * entry in that subdirectory. "lst" is the list of open FILEPTRs for
  158.  * this file. "length" is the actual length, "data" the actual data, and
  159.  * "avail" is the length of the ram block allocated for "data".
  160.  *
  161.  * Note that all the memory is allocated in one block: it may cause trouble
  162.  * with big files if the memory is fragmented.
  163.  */
  164.  
  165. typedef struct ramfile {
  166.     struct ramfile *next, *up, *down;
  167.     char filename[RAMFILE_MAX+1];
  168.     int uid, gid;
  169.     short time, date;
  170.     unsigned mode;
  171.     FILEPTR *lst;
  172.     long length, avail;
  173.     char *data;
  174. } RAMFILE;
  175.  
  176. RAMFILE ramroot, *trash;
  177. int ram_drive;
  178.  
  179. DEVDRV ram_device = {
  180.     ram_open, ram_write, ram_read, ram_lseek, ram_ioctl, ram_datime,
  181.     ram_close, ram_select, ram_unselect
  182. };
  183.  
  184. FILESYS ram_filesys = {
  185.     (FILESYS *)0,
  186.     FS_LONGPATH,
  187.     ram_root,
  188.     ram_lookup, ram_creat, ram_getdev, ram_getxattr,
  189.     ram_chattr, ram_chown, ram_chmode,
  190.     ram_mkdir, ram_rmdir, ram_remove, ram_getname, ram_rename,
  191.     ram_opendir, ram_readdir, ram_rewinddir, ram_closedir,
  192.     ram_pathconf, ram_dfree,
  193.     ram_writelabel, ram_readlabel, ram_symlink, ram_readlink,
  194.     ram_hardlink, ram_fscntl, ram_dskchng
  195. };
  196.  
  197. struct fs_descr ram_fs_descr = { &ram_filesys };
  198.  
  199. /*
  200.  * This function is called by the kernel when the
  201.  * file system is being loaded, and should return the file system
  202.  * structure
  203.  */
  204.  
  205. FILESYS *ram_init (struct kerinfo *k)
  206. {
  207.     kernel = k;
  208.  
  209.     CCONWS("Ramdisk filesystem for MiNT (Version " VERSION ", compiled " 
  210.     __DATE__ ") by T.Bousch\r\n");
  211.  
  212.     TRACE(("ram_init: initialize filesystem"));
  213.     ramroot.next = ramroot.up = ramroot.down = NULL;
  214.     ramroot.filename[0] = 0;
  215.     ramroot.uid  = ramroot.gid = 0;
  216.     ramroot.time = Timestamp();
  217.     ramroot.date = Datestamp();
  218.     ramroot.mode = S_IFDIR | DEFAULT_DIRMODE;
  219.     ramroot.lst  = NULL;
  220.     ramroot.length = ramroot.avail = 0;
  221.     ramroot.data = NULL;
  222.     trash = NULL;
  223.  
  224.     /* 
  225.      * We try first to install the filesystem as a gemdos-only drive
  226.      * because we don't want to pollute the bios drive map with a fake
  227.      * drive. Unfortunately, this will only work with recent MiNT
  228.      * versions (at least 1.08); with older versions we fallback
  229.      * to the previous method (install drive 'R').
  230.      */
  231.     if (DCNTL(FS_INSTALL, RAM_NAME, &ram_fs_descr) >= 0 &&
  232.         DCNTL(FS_MOUNT,   RAM_NAME, &ram_fs_descr) >= 0) {
  233.         ram_drive = ram_fs_descr.dev_no;
  234.         /* Tell the kernel that the filesystem is already loaded */
  235.         return (FILESYS*)(1L);
  236.     }
  237.     /* Add drive 'R' to the list of Bios drives */
  238.     ram_drive = 'R'-'A';
  239.     *(unsigned long *)(0x4c2L) |= (1UL << ram_drive);
  240.     return &ram_filesys;
  241. }
  242.  
  243. long ram_root (int drv, fcookie *fc)
  244. {
  245.     if (drv == ram_drive) {
  246.         TRACE(("ram_root: drive #%d is a ramdisk", drv));
  247.         fc->fs = &ram_filesys;
  248.         fc->dev = drv;
  249.         fc->index = (long) &ramroot;
  250.         return 0;
  251.     } else {
  252.         fc->fs = NULL;    /* Not our drive */
  253.         return EDRIVE;
  254.     }
  255. }
  256.  
  257. long ram_lookup (fcookie *dir, char *name, fcookie *fc)
  258. {
  259.     RAMFILE *s, *d;
  260.     
  261.     TRACE(("ram_lookup: search name [%s]", name));
  262.  
  263.     d = (RAMFILE *)dir->index;
  264.     
  265.     if (!d || !IS_DIRECTORY(d)) {
  266.         DEBUG(("ram_lookup: bad directory"));
  267.         return EPTHNF;
  268.     }
  269.     /* Empty name and "." are the directory itself */
  270.     if (!*name || !Stricmp(name, ".")) {
  271.         *fc = *dir;
  272.         return 0;
  273.     }
  274.     /* ".." could be a mount point */
  275.     if (!Stricmp(name, "..")) {
  276.         s = d->up;
  277.         if (s) {
  278.             fc->index = (long)s;
  279.             fc->fs = &ram_filesys;
  280.             fc->dev = ram_drive;
  281.             return 0;
  282.         } else {
  283.             *fc = *dir;
  284.             return EMOUNT;
  285.         }
  286.     }
  287.     
  288.     for (s = d->down; s; s = s->next) {
  289.         if (!Stricmp(s->filename,name))
  290.             break;
  291.     }    
  292.  
  293.     if (!s) {
  294.         DEBUG(("ram_lookup: name [%s] not found", name));
  295.         return EFILNF;
  296.     } else {
  297.         fc->index = (long)s;
  298.         fc->fs = &ram_filesys;
  299.         fc->dev = ram_drive;
  300.     }
  301.     return 0;
  302. }
  303.  
  304. /* How many files are there in a directory? */
  305.  
  306. static unsigned int count (RAMFILE *d)
  307. {
  308.     unsigned int n = 0;
  309.     RAMFILE *s;
  310.     
  311.     for (s = d->down; s; s = s->next)
  312.         ++n;
  313.     return n;
  314. }
  315.  
  316. long ram_getxattr (fcookie *fc, XATTR *xattr)
  317. {
  318.     RAMFILE *s;
  319.     
  320.     TRACE(("ram_getxattr: get file attributes"));
  321.     
  322.     xattr->blksize = BLKSIZE;
  323.     xattr->dev = ram_drive;
  324.     xattr->nlink = 1;
  325.     s = (RAMFILE *)fc->index;
  326.     xattr->index = (long)s;
  327.     xattr->uid = s->uid; xattr->gid = s->gid;
  328.     xattr->size =
  329.         (IS_DIRECTORY(s) ? count(s) * sizeof(RAMFILE) : s->length);
  330.         xattr->nblocks = (s->avail + BLKSIZE - 1) / BLKSIZE;
  331.     xattr->mtime = xattr->ctime = xattr->atime = s->time;
  332.     xattr->mdate = xattr->cdate = xattr->adate = s->date;
  333.     xattr->mode = s->mode;
  334.     xattr->attr = ((s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ? 0 : FA_RDONLY)
  335.             | (IS_DIRECTORY(s) ? FA_DIR : 0);
  336.     return 0;
  337. }
  338.  
  339. long ram_chattr (fcookie *fc, int attrib)
  340. {
  341.     RAMFILE *s;
  342.     
  343.     TRACE(("ram_chattr: new attrib 0%o", attrib));
  344.  
  345.     s = (RAMFILE *)fc->index;
  346.     if (attrib & FA_RDONLY) {
  347.         s->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  348.     } else if ( !(s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ) {
  349.         s->mode |= (S_IWUSR|S_IWGRP|S_IWOTH);
  350.     }
  351.     return 0;
  352. }
  353.  
  354. long ram_chown (fcookie *fc, int uid, int gid)
  355. {
  356.     RAMFILE *s;
  357.     
  358.     TRACE(("ram_chown: new owner is %d.%d", uid, gid));
  359.  
  360.     s = (RAMFILE *)fc->index;
  361.     s->uid = uid;
  362.     s->gid = gid;
  363.     return 0;
  364. }
  365.  
  366. long ram_chmode (fcookie *fc, unsigned mode)
  367. {
  368.     RAMFILE *s;
  369.     
  370.     TRACE(("ram_chmode: new mode 0%o", mode));
  371.  
  372.     s = (RAMFILE *)fc->index;
  373.     s->mode = (s->mode & S_IFMT) | (mode & ~S_IFMT);
  374.     return 0;
  375. }
  376.  
  377. /*
  378.  * Deletes file "s" if it's on the trash-list and no longer used,
  379.  * i.e. (s->lst == NULL).
  380.  */
  381.  
  382. static void _unlink (RAMFILE *s)
  383. {
  384.     RAMFILE *t, **old;
  385.  
  386.     if (s->lst == NULL) {    
  387.         old = &trash;
  388.         for (t = trash; t && t != s; t = t->next)
  389.             old = &t->next;
  390.         if (t) {
  391.             *old = s->next;
  392.             Kfree(s->data);
  393.             Kfree(s);
  394.         }
  395.     }
  396. }
  397.  
  398. /*
  399.  * Deletes a file from the current directory, moving it into
  400.  * the trash-list.
  401.  */
  402.  
  403. static void unlink (RAMFILE *s)
  404. {
  405.     RAMFILE *d, *t, **old;
  406.  
  407.     d = s->up;
  408.     old = &d->down;
  409.     for (t = d->down; t && t != s; t = t->next)
  410.         old = &t->next;
  411.     if (!t) {
  412.         ALERT(("ram_unlink: file not found"));
  413.         return;
  414.     }
  415.     *old = s->next;
  416.  
  417.     /* Now move the file into the trash */
  418.     s->next = trash;
  419.     trash = s;
  420.     _unlink(s);
  421. }
  422.  
  423. /* Is a filename valid ? */
  424.  
  425. static int valid_name (char *name)
  426. {
  427.     char c;
  428.  
  429.     if (!name || !*name || !Stricmp(name,".") || !Stricmp(name,".."))
  430.         return 0;        /* Reserved */
  431.  
  432.     while ((c = *name++) != 0) {
  433.         if (c < 32 || c > 126)
  434.             return 0;    /* Non-ASCII character met */
  435.         if (c == '/' || c == '\\' || c == ':')
  436.             return 0;    /* Directory separator */
  437.     }
  438.     return 1;
  439. }
  440.  
  441. long ram_remove (fcookie *dir, char *name)
  442. {
  443.     RAMFILE *d, *s;
  444.     
  445.     TRACE(("ram_remove: delete file [%s]", name));
  446.  
  447.     d = (RAMFILE *)dir->index;
  448.     for (s = d->down; s; s = s->next) {
  449.         if (!Stricmp(s->filename, name))
  450.             break;
  451.     }
  452.     if (!s) {
  453.         DEBUG(("ram_remove: file [%s] not found", name));
  454.         return EFILNF;
  455.     }
  456.     if (IS_DIRECTORY(s)) {
  457.         DEBUG(("ram_remove: [%s] is a directory", name));
  458.         return EACCDN;
  459.     }
  460.     /* If d is sticky, check that we own the file */
  461.     if (IS_STICKY(d) && Geteuid() && s->uid != Getuid()) {
  462.         DEBUG(("ram_remove: not owner"));
  463.         return EACCDN;
  464.     }
  465.     unlink(s);    
  466.     return 0;
  467. }
  468.  
  469. long ram_getname (fcookie *root, fcookie *dir, char *path, int size)
  470. {
  471.     RAMFILE *s, *d;
  472.     char p[RAMFILE_MAX+2];
  473.  
  474.     if (size <= 0) return ERANGE;
  475.     path[0] = 0;    /* empty string */
  476.     d = (RAMFILE *)root->index;
  477.     s = (RAMFILE *)dir->index;
  478.     while (s) {
  479.         if (s == d) {
  480.             strrev(path);
  481.             TRACE(("ram_getname: returned [%s]", path));
  482.             return 0;
  483.         }
  484.         p[0] = '\\';
  485.         strcpy(p+1, s->filename);
  486.         strrev(p);
  487.         size -= strlen(p);
  488.         if (size <= 0) {
  489.             DEBUG(("ram_getname: name too long"));
  490.             path[0] = 0;
  491.             return ENAMETOOLONG;
  492.         }
  493.         strcat(path, p);
  494.         s = s->up;
  495.     }
  496.     DEBUG(("ram_getname: path not found"));
  497.     path[0] = 0;
  498.     return EPTHNF;    /* not found */
  499. }
  500.  
  501. long ram_rename (fcookie *olddir, char *oldname,
  502.             fcookie *newdir, char *newname)
  503. {
  504.     RAMFILE *s, *d, *dold, *dnew, **old;
  505.     
  506.     TRACE(("ram_rename: mv %s %s", oldname, newname));
  507.  
  508.     /* Verify that "newname" doesn't exist */
  509.     if (!valid_name(newname)) {
  510.         DEBUG(("ram_rename: invalid filename"));
  511.         return EACCDN;
  512.     }
  513.     dnew = (RAMFILE *)newdir->index;
  514.     for (s = dnew->down; s; s = s->next)
  515.         if (!Stricmp(s->filename, newname)) {
  516.             DEBUG(("ram_rename: file already exists"));
  517.             return EACCDN;
  518.         }
  519.     /* Verify that "oldname" exists */
  520.     dold = (RAMFILE *)olddir->index;
  521.     old = &dold->down;
  522.     for (s = dold->down; s; s = s->next)
  523.         if (!Stricmp(s->filename, oldname))
  524.             break;
  525.         else    old = &s->next;
  526.     if (!s) {
  527.         DEBUG(("ram_rename: file not found"));
  528.         return EFILNF;
  529.     }
  530.     /* Verify that "newdir" is not a subdirectory of "name" */
  531.     for (d = dnew; d; d = d->up)
  532.         if (d == s) {
  533.             DEBUG(("ram_rename: invalid move"));
  534.             return EACCDN;
  535.         }
  536.     /* If dold is sticky, check that we own the file */
  537.     if (IS_STICKY(dold) && Geteuid() && s->uid != Getuid()) {
  538.         DEBUG(("ram_rename: not owner"));
  539.         return EACCDN;
  540.     }
  541.     /* Ok... The file can be renamed now. */
  542.     strncpy(s->filename, newname, RAMFILE_MAX);
  543.     s->filename[RAMFILE_MAX] = 0;
  544.     if (dold != dnew) {
  545.         /* Rename across directories */
  546.         TRACE(("ram_rename: move across directories"));
  547.         *old = s->next;
  548.         s->next = dnew->down;
  549.         dnew->down = s;
  550.         s->up = dnew;
  551.     }
  552.     dold->time = dnew->time = Timestamp();
  553.     dold->date = dnew->date = Datestamp();
  554.  
  555.     return 0;
  556. }
  557.  
  558. long ram_opendir (DIR *dirh, int flags)
  559. {
  560.     RAMFILE *d;
  561.     
  562.     TRACE(("ram_opendir: open directory"));
  563.  
  564.     dirh->index = 0;
  565.     d = (RAMFILE *)dirh->fc.index;
  566.     *(RAMFILE **)(&dirh->fsstuff) = d->down;    /* next file */
  567.  
  568.     return 0;
  569. }
  570.  
  571. long ram_rewinddir (DIR *dirh)
  572. {
  573.     RAMFILE *d;
  574.     
  575.     TRACE(("ram_rewinddir: rewind directory"));
  576.  
  577.     dirh->index = 0;
  578.     d = (RAMFILE *)dirh->fc.index;
  579.     *(RAMFILE **)(&dirh->fsstuff) = d->down;    /* next file */
  580.  
  581.     return 0;
  582.  
  583. }
  584.  
  585. long ram_closedir (DIR *dirh)
  586. {
  587.     TRACE(("ram_closedir: close directory"));
  588.     return 0;
  589. }
  590.  
  591. long ram_readdir (DIR *dirh, char *name, int namelen, fcookie *fc)
  592. {
  593.     int i;
  594.     int giveindex = (dirh->flags == 0);
  595.     RAMFILE *s;
  596.     char *Filename;
  597.     
  598.     i = dirh->index++;
  599.     s = (RAMFILE *)dirh->fc.index;    /* Current directory */
  600.     if (i == 0) {
  601.         /* The "." entry is the first one */
  602.         Filename = ".";
  603.     } else if (i == 1 && s->up != NULL) {
  604.         /* The ".." entry is the second one */
  605.         s = s->up;
  606.         Filename = "..";
  607.     } else {
  608.         /* Any regular entry */
  609.         s = *(RAMFILE **)(&dirh->fsstuff);
  610.         if (!s) {
  611.             TRACE(("ram_readdir: no more files"));
  612.             return ENMFIL;
  613.         }
  614.         *(RAMFILE **)(&dirh->fsstuff) = s->next;
  615.         Filename = s->filename;
  616.     }
  617.     TRACE(("ram_readdir: entry %d: %s", i, Filename));
  618.     
  619.     fc->index = (long)s;
  620.     fc->fs = &ram_filesys;
  621.     fc->dev = ram_drive;
  622.     
  623.     if (giveindex) {
  624.         namelen -= (int)sizeof(long);
  625.         if (namelen <= 0) return ERANGE;
  626.         *((long *)name) = (long)s;
  627.         name += sizeof(long);
  628.     }
  629.     if (namelen <= strlen(Filename)) {
  630.         DEBUG(("ram_readdir: name too long"));
  631.         return ENAMETOOLONG;
  632.     }
  633.     strcpy(name, Filename);
  634.     return 0;
  635. }
  636.     
  637. long ram_pathconf (fcookie *dir, int which)
  638. {
  639.     TRACE(("ram_pathconf: limit %d", which));
  640.  
  641.     switch(which) {
  642.     case -1:
  643.         return DP_MAXREQ;
  644.     case DP_IOPEN:
  645.         return UNLIMITED;    /* no internal limit on open files */
  646.     case DP_MAXLINKS:
  647.         return 1;        /* we don't have hard links */
  648.     case DP_PATHMAX:
  649.         return UNLIMITED;    /* max. path length */
  650.     case DP_NAMEMAX:
  651.         return RAMFILE_MAX;    /* max. length of individual name */
  652.     case DP_ATOMIC:
  653.         return UNLIMITED;    /* all writes are atomic */
  654.     case DP_TRUNC:
  655.         return DP_AUTOTRUNC;    /* file names are truncated */
  656.     case DP_CASE:
  657.         return DP_CASEINSENS;    /* case preserved but ignored */
  658.     default:
  659.         DEBUG(("ram_pathconf: invalid parameter"));
  660.         return EINVFN;
  661.     }
  662. }
  663.  
  664. /*
  665.  * The following (recursive) function calculates the total size of a
  666.  * file or directory, including the RAMFILE structure
  667.  */
  668.  
  669. static long mem_used (RAMFILE *d)
  670. {
  671.     long used;
  672.     RAMFILE *s;
  673.     
  674.     if (!IS_DIRECTORY(d))
  675.         return sizeof(RAMFILE) + (d->avail);
  676.     /* If it is a directory, then */
  677.     used = sizeof(RAMFILE);
  678.     for (s = d->down; s; s = s->next)
  679.         used += mem_used(s);
  680.     return used;
  681. }
  682.  
  683. long ram_dfree (fcookie *dir, long *buf)
  684. {
  685.     long memfree, memused;
  686.     
  687.     TRACE(("ram_dfree: getting free disk space"));
  688.  
  689.     memfree = FreeMemory();
  690.     memused = mem_used(&ramroot);
  691.  
  692.     *buf++ = memfree / BLKSIZE;        /* free blocks        */
  693.     *buf++ = (memfree + memused) / BLKSIZE;    /* total nb of blocks */
  694.     *buf++ = BLKSIZE;            /* sector size        */
  695.     *buf   = 1;                /* 1 sector per block */
  696.     
  697.     return 0;
  698. }
  699.  
  700. long ram_writelabel (fcookie *dir, char *name)
  701. {
  702.     DEBUG(("ram_writelabel: not implemented"));
  703.     return EINVFN;
  704. }
  705.  
  706. long ram_readlabel (fcookie *dir, char *name, int namelen)
  707. {
  708.     DEBUG(("ram_readlabel: not implemented"));
  709.     return EINVFN;
  710. }
  711.  
  712. long ram_hardlink (fcookie *fromdir, char *fromname,
  713.             fcookie *todir, char *toname)
  714. {
  715.     DEBUG(("ram_hardlink: invalid function"));
  716.     return EINVFN;
  717. }
  718.  
  719. long ram_fscntl (fcookie *dir, char *name, int cmd, long arg)
  720. {
  721.     DEBUG(("ram_fscntl: nothing available"));
  722.     return EINVFN;    /* Nothing for now */
  723. }
  724.  
  725. long ram_dskchng (int drv)
  726. {
  727.     TRACE(("ram_dskchng: ram disk changed ?"));
  728.     return 0; /* No media change on a ram disk! */
  729. }
  730.  
  731. DEVDRV *ram_getdev (fcookie *fc, long *devsp)
  732. {
  733.     RAMFILE *s;
  734.     
  735.     TRACE(("ram_getdev: find device driver"));
  736.  
  737.     s = (RAMFILE *)fc->index;
  738.     *devsp = (long)s;
  739.     return &ram_device;
  740. }
  741.  
  742. /*
  743.  * Create a ram file. This function is used for regular files _and_
  744.  * directories
  745.  */
  746.  
  747. static long 
  748. create_ram_file (fcookie *dir, char *name, unsigned mode, fcookie *fc)
  749. {
  750.     RAMFILE *s, *d;
  751.  
  752.     TRACE(("create_ram_file: file [%s] mode 0%o", name, mode));
  753.     
  754.     /* Does this name already exist ? */
  755.     if (!valid_name(name)) {
  756.         DEBUG(("create_ram_file: invalid filename"));
  757.         return EACCDN;
  758.     }
  759.     d = (RAMFILE *)dir->index;
  760.     for (s = d->down; s; s = s->next) {
  761.         if (!Stricmp(s->filename, name)) {
  762.             DEBUG(("create_ram_file: file exists"));
  763.             return EACCDN;
  764.         }
  765.     }
  766.     s = (RAMFILE *)Kmalloc(sizeof(RAMFILE));
  767.     if (!s) {
  768.         ALERT(("create_ram_file: out of memory"));
  769.         return ENSMEM;
  770.     }
  771.     strncpy(s->filename, name, RAMFILE_MAX);
  772.     s->filename[RAMFILE_MAX] = 0;
  773.     /*
  774.      * If the directory has the bits Setuid or Setgid set, then the
  775.      * file inherits the uid or gid of its parent:
  776.      */
  777.     s->uid = IS_SETUID(d) ? d->uid : Getuid();
  778.     s->gid = IS_SETGID(d) ? d->gid : Getgid();
  779.     s->mode = mode;
  780.     s->lst  = NULL;
  781.     s->length = s->avail = 0;
  782.     s->data = NULL;
  783.     s->time = d->time = Timestamp();
  784.     s->date = d->date = Datestamp();
  785.     s->next = d->down;
  786.     d->down = s;
  787.     s->down = NULL;
  788.     s->up   = d;
  789.     
  790.     fc->fs = &ram_filesys;
  791.     fc->index = (long)s;
  792.     fc->dev = dir->dev;
  793.     
  794.     return 0;
  795. }
  796.  
  797. long ram_creat (fcookie *dir, char *name, unsigned mode,
  798.             int attrib, fcookie *fc)
  799. {
  800.     TRACE(("ram_creat: create regular file"));
  801.     return create_ram_file (dir, name, mode|S_IFREG, fc);
  802. }
  803.  
  804. long ram_mkdir (fcookie *fc, char *name, unsigned mode)
  805. {
  806.     fcookie Fc;
  807.     
  808.     TRACE(("ram_mkdir: make directory"));
  809.     return create_ram_file (fc, name, mode|S_IFDIR, &Fc);
  810. }
  811.  
  812. long ram_rmdir (fcookie *dir, char *name)
  813. {
  814.     RAMFILE *d, *s;
  815.     
  816.     TRACE(("ram_rmdir: remove directory [%s]", name));
  817.  
  818.     d = (RAMFILE *)dir->index;
  819.     for (s = d->down; s; s = s->next) {
  820.         if (!Stricmp(s->filename, name))
  821.             break;
  822.     }
  823.     if (!s) {
  824.         DEBUG(("ram_rmdir: directory [%s] not found", name));
  825.         return EFILNF;
  826.     }
  827.     if (!IS_DIRECTORY(s) && !IS_SYMLINK(s)) {
  828.         DEBUG(("ram_rmdir: [%s] isn't a directory", name));
  829.         return EACCDN;
  830.     }
  831.     if (IS_DIRECTORY(s) && s->down) {
  832.         DEBUG(("ram_rmdir: directory [%s] isn't empty", name));
  833.         return EACCDN;
  834.     }
  835.     /* If d is sticky, check that we own the subdirectory */
  836.     if (IS_STICKY(d) && Geteuid() && s->uid != Getuid()) {
  837.         DEBUG(("ram_rmdir: not owner"));
  838.         return EACCDN;
  839.     }
  840.     unlink(s);
  841.     return 0;
  842. }
  843.  
  844. long ram_symlink (fcookie *dir, char *name, char *to)
  845. {
  846.     RAMFILE *s;
  847.     fcookie Fc; 
  848.     long ret, len;
  849.  
  850.     TRACE(("ram_symlink: create symbolic link"));
  851.  
  852.     ret = create_ram_file (dir, name, 0777|S_IFLNK, &Fc);
  853.     if (ret == 0) {
  854.         s = (RAMFILE *)Fc.index;
  855.         len = strlen(to) + 1;
  856.         s->data = Kmalloc(len);
  857.         if (!s->data) {
  858.             ALERT(("ram_symlink: out of memory"));
  859.             unlink(s);
  860.             return ENSMEM;
  861.         }
  862.         s->length = s->avail = len;
  863.         strcpy(s->data, to);
  864.     }
  865.     return ret;
  866. }
  867.  
  868. long ram_readlink (fcookie *dir, char *buf, int len)
  869. {
  870.     RAMFILE *s;
  871.  
  872.     s = (RAMFILE *)dir->index;
  873.     if (!IS_SYMLINK(s)) {
  874.         DEBUG(("ram_readlink: not a symbolic link"));
  875.         return EACCDN;
  876.     }
  877.     if (s->length > len) {
  878.         DEBUG(("ram_readlink: name too long"));
  879.         return ENAMETOOLONG;
  880.     }
  881.     strcpy(buf, s->data);
  882.     TRACE(("ram_readlink: returned [%s]", buf));
  883.     return 0;
  884. }
  885.  
  886. /*
  887.  * The ram disk driver
  888.  */
  889.  
  890. static void realloc_ramfile (RAMFILE *s, long new_size)
  891. {
  892.     char *data2;
  893.     long quantum, bytes;
  894.     
  895.     /* We choose bigger blocks for big files */
  896.     quantum = (new_size > 16*BLKSIZE) ? 4*BLKSIZE : BLKSIZE;
  897.     /* 
  898.      * Round to the next multiple of quantum; we assume that 
  899.      * quantum is a power of two !!
  900.      */
  901.     new_size = (new_size + quantum - 1) & ~(quantum - 1);
  902.     data2 = new_size ? (char *)Kmalloc(new_size) : NULL;
  903.     if (!new_size || data2) {
  904.         bytes = s->length;
  905.         if (bytes > new_size)
  906.             bytes = new_size;
  907.         bcopy(s->data, data2, bytes);
  908.         Kfree(s->data);
  909.         s->data = data2;
  910.         s->avail = new_size;
  911.         if (s->length > s->avail)
  912.             s->length = s->avail;
  913.     } else    ALERT(("realloc_ramfile: out of memory"));
  914. }
  915.  
  916. long ram_open (FILEPTR *f)
  917. {
  918.     RAMFILE *s;
  919.  
  920.     TRACE(("ram_open: open file"));
  921.  
  922.     s = (RAMFILE *)f->devinfo;
  923.     /* Check the sharing mode */
  924.     if (Denyshare(s->lst, f)) {
  925.         DEBUG(("ram_open: sharing modes conflict"));
  926.         return EACCDN;
  927.     }
  928.     if (f->flags & O_TRUNC) {
  929.         /* truncate the file */
  930.         realloc_ramfile(s, 0);
  931.     }
  932.     f->next = s->lst;
  933.     s->lst = f;
  934.     
  935.     return 0;
  936. }
  937.  
  938. long ram_close (FILEPTR *f, int pid)
  939. {
  940.     RAMFILE *s;
  941.     FILEPTR **old, *g;
  942.     
  943.     TRACE(("ram_close: close file"));
  944.  
  945.     if (f->links == 0) {
  946.         s = (RAMFILE *)f->devinfo;
  947.         old = &(s->lst);
  948.         for (g = s->lst; g && g != f; g = g->next)
  949.             old = &(g->next);
  950.         if (!g)
  951.             ALERT(("ram_close: FILEPTR not found"));
  952.         else    *old = f->next;
  953.  
  954.         _unlink(s);
  955.     }
  956.     return 0;
  957. }
  958.  
  959. long ram_write (FILEPTR *f, char *buf, long nbytes)
  960. {
  961.     RAMFILE *s;
  962.     long new_size;
  963.     
  964.     s = (RAMFILE *)f->devinfo;
  965.     new_size = nbytes + f->pos;
  966.     if (new_size > s->avail)
  967.         realloc_ramfile(s, new_size);
  968.     /* Hope that the file is big enough now */
  969.     if (new_size > s->avail)
  970.         nbytes = s->avail - f->pos;
  971.     if (nbytes < 0)
  972.         nbytes = 0;
  973.     /* Copy the data */
  974.     TRACE(("ram_write: %ld bytes from pos %ld", nbytes, f->pos));
  975.     bcopy(buf, s->data + f->pos, nbytes);
  976.  
  977.     /* Update the file status */
  978.     f->pos += nbytes;
  979.     if (f->pos > s->length)
  980.         s->length = f->pos;
  981.     if (s->length > s->avail)
  982.         s->length = s->avail;
  983.     s->time = Timestamp();
  984.     s->date = Datestamp();
  985.  
  986.     return nbytes;
  987. }
  988.         
  989. long ram_read (FILEPTR *f, char *buf, long nbytes)
  990. {
  991.     RAMFILE *s;
  992.  
  993.     s = (RAMFILE *)f->devinfo;
  994.     if (nbytes + f->pos > s->length)
  995.         nbytes = s->length - f->pos;
  996.     if (nbytes < 0)
  997.         nbytes = 0;
  998.     /* Copy the data */
  999.     TRACE(("ram_read: %ld bytes from pos %ld", nbytes, f->pos));
  1000.     bcopy(s->data + f->pos, buf, nbytes);
  1001.     f->pos += nbytes;
  1002.     
  1003.     return nbytes;
  1004. }
  1005.  
  1006. /* File locking code not yet implemented */
  1007.  
  1008. long ram_ioctl (FILEPTR *f, int mode, void *buf)
  1009. {
  1010.     RAMFILE *s;
  1011.     long new_size;
  1012.  
  1013.     TRACE(("ram_ioctl: mode %d", mode));
  1014.     s = (RAMFILE *)f->devinfo;
  1015.     if (mode == FIONREAD || mode == FIONWRITE) {
  1016.         *((long *)buf) = 1;
  1017.         return 0;
  1018.     } else if (mode == F_SETLK || mode == F_GETLK) {
  1019.         DEBUG(("ram_ioctl: locking not implemented"));
  1020.         return EINVFN;
  1021.     } else if (mode == FTRUNCATE) {
  1022.         new_size = *((long *)buf);
  1023.         if (new_size < 0) {
  1024.             DEBUG(("ram_ioctl: can't truncate file"));
  1025.             return ERANGE;
  1026.         }
  1027.         /* Reallocate the memory block */
  1028.         realloc_ramfile(s, new_size);
  1029.         if (new_size > s->avail) {
  1030.             DEBUG(("ram_ioctl: can't truncate file"));
  1031.             return ENSMEM;
  1032.         }
  1033.         s->length = new_size;
  1034.         return 0;
  1035.     }
  1036.     DEBUG(("ram_ioctl: invalid function"));
  1037.     return EINVFN;
  1038. }
  1039.  
  1040. long ram_lseek(FILEPTR *f, long where, int whence)
  1041. {
  1042.     RAMFILE *s;
  1043.     long newpos;
  1044.  
  1045.     TRACE(("ram_lseek: goto %ld, mode %d", where, whence));
  1046.     
  1047.     s = (RAMFILE *)f->devinfo;
  1048.     
  1049.     switch(whence) {
  1050.     case 0:
  1051.         newpos = where;
  1052.         break;
  1053.     case 1:
  1054.         newpos = f->pos + where;
  1055.         break;
  1056.     case 2:
  1057.         newpos = s->length - where;
  1058.         break;
  1059.     default:
  1060.         DEBUG(("ram_lseek: invalid mode"));
  1061.         return EINVFN;
  1062.     }
  1063.     
  1064.     if (newpos < 0) {
  1065.         TRACE(("ram_lseek: out of range"));
  1066.         return ERANGE;
  1067.     }
  1068.     f->pos = newpos;
  1069.     return newpos;
  1070. }
  1071.  
  1072. long ram_datime (FILEPTR *f, int *timeptr, int rwflag)
  1073. {
  1074.     RAMFILE *s;
  1075.     
  1076.     s = (RAMFILE *)f->devinfo;
  1077.     if (rwflag) {
  1078.         TRACE(("ram_datime: set time and date"));
  1079.         s->time = *timeptr++;
  1080.         s->date = *timeptr;
  1081.     } else {
  1082.         TRACE(("ram_datime: get time and date"));
  1083.         *timeptr++ = s->time;
  1084.         *timeptr   = s->date;
  1085.     }
  1086.     return 0;
  1087. }
  1088.  
  1089. long ram_select (FILEPTR *f, long p, int mode)
  1090. {
  1091.     TRACE(("ram_select: always ready"));
  1092.     return 1;
  1093. }
  1094.  
  1095. void ram_unselect (FILEPTR *f, long p, int mode)
  1096. {
  1097.     TRACE(("ram_unselect: nothing to do"));
  1098.     /* Nothing for us to do */
  1099. }
  1100.